Глава
7
Cookies в
CFML
Cookies,
так называемое "печенье" или, как еще иногда упоминают в литера-Туре,
ячейки, позволяет хранить информацию на стороне клиента для последующего использования.
Это может быть информация о клиенте, воспользовавшемся услугами сайта, о содержимом
"покупательской корзины" в электронном магазине, о действиях, произведенных
клиентом по отношению к расположенным на странице элементам формы.
Cookie является
решением одной из проблем протокола HTTP (HyperText Transfer Protocol, протокол
передачи гипертекста), которая заключается в непостоянстве соединения между
клиентом и сервером. Включение cookie в HTTP-протокол способствовало частичному
решению этой проблемы. То есть транзакция завершается после того, как браузер
сделал запрос, а сервер выдал соответствующий ответ. Сразу после этого сервер
"забывает" о пользователе и каждый следующий запрос того же пользователя
считает переданным новым пользователем.
С помощью
cookie можно эмулировать сессию по HTTP-протоколу. Принцип эмуляции сессии таков:
на первом запросе выдается соответствующее значение cookie, а при каждом последующем
запросе это значение читается из переменной окружения HTTP_COOKIE и соответствующим
образом обрабатывается.
Cookie
— это небольшая порция текстовой информации, которую сервер передает браузеру.
Браузер будет хранить эту информацию и передавать ее серверу с каждым запросом
как часть HTTP-заголовка. Некоторые значения cookie могут храниться только в
течение одной сессии и удаляются после закрытия браузера. Другие, настроенные
на определенный период времени, записываются в файл. Обычно этот файл называется
cookies.txt и размещается в рабочем каталоге установленного на компьютере браузера.
Синтаксис:
<CFCOOKIE
NAME="cookie_name" VALUE="text"
EXPIRES="period"
SECURE="Yes
| No" PATH="urls" DOMAIN=".domain">
В табл. 7.1
представлено описание атрибутов тега <CFCOOKIE>.
Таблица
7.1. Описание атрибутов тега <CFCOOKIE>
Атрибут |
Описание |
||
NAME
VALUE
EXPIRES
SECURE
PATH
DOMAIN |
Название переменной
cookie. Обязательный атрибут Значение переменной cookie. Необязательный
атрибут Планирует жизненный
цикл переменной cookie. Может быть определен как дата (например, 12/31/2001),
число дней (например, 10), Now (сейчас) или Never (никогда). Использование
значения Now удаляет cookie из клиентского браузера. Является необязательным
атрибутом и если не указывается, то cookie хранится в течение одного
сеанса, до закрытия браузера Указывает, что
переменная должна быть передана по надежному каналу. Если этот атрибут
имеет значение Yes, то информация cookie пересылается только через
HTTPS (HTTP с использованием SSL, Secure Socket Level) в защищенном
режиме. Иначе информация пересылается обычным способом. В случае использования
защищенного режима и отсутствия на клиентском браузере SSL, cookie
не будет создан. Необязательный атрибут Этот атрибут
определяет подмножество документов, для которых действительно значение
cookie. Например, указание path="/my" приведет к тому, что
значение cookie будет действительно для множества документов в каталогах
/ту-арр1/, /mу-арр2/ и файлов в текущем каталоге с именами типа myfile1.html
' и myfile2.shtml. Для того чтобы cookie отсылались при каждом запросе
к серверу, необходимо указать корневой каталог сервера, например,
path="/". Для перечисления нескольких значений необходимо
использовать разделитель ; (точку с запятой). Необязательный атрибут Домен, для которого
значение cookie действительно. Указанное значение должно всегда начинаться
с точки, например, domain=" .Akhayan.com". Для перечисления
нескольких значений необходимо использовать разделитель ; (точку с
запятой). При использовании атрибута PATH необходимо указывать и атрибут
DOMAIN |
||
Cookies,
написанные с использованием тега <CFCOOKIE>, не сохраняются в файле cookies.txt
до конца сессии браузера. Пока браузер открыт, cookie хранится
в памяти. Если атрибут EXPIRES не указан, cookie не записывается в файл cookies.txt
и существует до завершения сессии браузера.
Если cookie
принимает новое значение при имеющемся уже в браузере cookie с совпадающими
атрибутами NAME, DOMAIN и PATH, то старое значение заменяется новым. В остальных
случаях новые значения cookie добавляются к старым.
Использование
атрибута EXPIRES не гарантирует сохранность cookie в течение заданного периода
времени, поскольку клиент (браузер) может удалить запись из-за нехватки выделенного
места или по каким-либо другим причинам.
Клиент (браузер)
имеет следующие ограничения для cookies:
Если ограничение
300 или 20 превышается, то удаляется первая по времени запись. При превышении
лимита объема в 4 Кбайт корректность значения cookie страдает — отсекается кусок
записи (с начала этой записи), равный превышению объема.
Пример
использования тега <CFCOOKIE>
Предположим,
нам необходимо создать первую страницу сайта, предоставляющего информацию о
круизах из Нью-Йорка, с предварительным запросом о национальном языке просмотра.
При этом по согласованию с пользователем, в дальнейшем чтобы больше не озадачивать
его подобными вопросами, в течение недели необходимо сразу загружать информацию
на родном ему языке. Более того, немного усложним задачу: при загрузке выбранной
пользователем страницы необходимо открывать окно с дополнительной информацией
в течение всего времени до обусловленной даты. В качестве дополнительной информации
может быть расписание сезонных рейсов, имеющее силу до определенного момента,
или реклама с определенными сроками действия, или еще что-либо.
Решение данной
задачи может быть следующим. Во-первых, нужно решить, сколько мы будем использовать
cookies, а во-вторых, каким будет жизненный цикл для каждого cookie. Нам необходимо
два cookies: первый будет определять выбранный язык, а второй — загрузку окна
с дополнительной информацией. Для первого cookie, назовем его language, исходя
из задачи, жизненный цикл укажем в семь дней. Для второго cookie, назовем его
commercial, жизненный цикл зададим до конца 2001 года.
Следовательно,
определение наших "пирожков" будет выглядеть следующим образом:
<CFCOOKIE
NAME="language"
VALUE="#languagei"
EXPIRES="7">
где #language#
— значение переменной.
<CFCOOKIE
NAME="commercial" VALUE="1" EXPIRES="12/31/2001">
Заметим,
что "пирожок" commercial, будет "съеден" в ночь с 30 на
31 декабря 2001 года, а 31 числа от него уже ничего не останется, если только
до этого момента он не будет "проглочен" клиентом браузера.
Для того
чтобы прочитать значение cookie, в CFML используется конструкция cookie.Name,
где Name — наименование cookie. Например:
<CFIF isDefined{"Cookie.language")>
<CFSET language=#Cookie.language#>
</CFIF>
В этом коде
проверяем наличие cookie с названием-language, и если такой существует, создаем
переменную с подобным именем, определяя ей значение В соответствии с Cookie,
language.
Далее продемонстрируем
полный код страницы myjine.cfm, позволяющей решить поставленную выше задачу
(листинг 7.1).
Листинг
7.1. Код страницы myjine.cfm
<HTML>
<HEAD>
<МЕТА http-equiv="Content-Type"
content="text/html;
charset=windows-1251">
<META name="Author" content="Ruben Akhayan">
<META http-equiv="Description" content="Cookies">
<TITLE>My-Line
Cruises</TITLE> </HEAD>
<style type="text/css">
<!—-
.clRemLang {
padding : Opx; font-weight : normal;
font-family : Verdana, Geneva, Arial, Helvetica, sans-serif;
font-size : llpx; color : #OOOOOO; }
. clPrompt {
padding : Opx;
ront-welgnt ; bolder >
font-family : Verdana, Geneva, Arial/ Helvetica, sans-serif,
-font-size : llpx; color : #666699;
} #prompt {position:
absolute; left: 10; top: 51; width: 406;
height: 10;
margin: 0; z- index: 1; } -->
</style>
<script>
var ns = (document. layers) ? true:
false var ie
= (document .all) ? true: false
function layerWrite
(id,nestref , text) { if (ns) {
var lyr = (nestref)?
eval ( 'document . '+nestref+' .document . '+id+
'.document') : document . layers [id] .document lyr . open ( ) lyr .write (text) lyr
.close ()
} else if (ie)
document .all [id] . innerHTML = text
}
function myLink(lang)
{
linecommand
= "window.location.href = 'my_line.cfm?language="+
lang+"&remlang='#document.forml.RemLang.value+"'";
eval (linecoiranand) ;
}
function chbRemLang(value) {
if (value=='Yes')
{
document.forml
.RemLang.value = 'No';
} else {
document. forml.RemLang.
value = 'Yes'
} }
</script>
<BODY>
<!--- Проверка
наличия переменных --->
<CFIF isDefined("Cookie.language") OR isDefined("language")>
<script>document.bgColor="#666699";</script>
<CFIF isDefined("Cookie.language")>
<CFSET language=#Cookie.language#>
</CFIF>
<CFIF isDefined("remlang")>
<CFIF remlang
eq "Yes">
<!--- Устанавливаем
Cookie-"language" --->
<CFCOOKIE
NftME="language"
VALUE="#language#"
EXPIRES="7"> </CFIF>
</CFIF>
<TABLE border='0' cellspacing='9' cellpadding='0'>
<TR><TD
align="center" colspan="2">
<FONT size="5"
color="White" face="Futura ><Blk BT">
MY-LINE CRUISES
</FONTX/TD></TR>
<TRXTD bgcolor="White" height=l colspan="2"></td></tr>
<TR><TD><img
src="fotoNY.gif" alt="" border="0"></td>
<TR><TD>
<FONT size="2" color="White" face="Arial"?
<CFSWITCH EXPRE5SION=#language#> <CFCASE VALUE="rus"> <br>
<br> (My
Line).<br>
</CFCASE>
<CFCASE VALUE="eng">
Discover why
over 50 million people<br>
have chosen
My Line as the best way to see New York.<br>
</CFCASE>
<CFCASE VALUE="ger">
Wie bereits
mehr als 50 Millionnen Besucher vir Ihnen,
erleben und<br>
entdecken auch
Sie New York bei einer Fahrt auf ainem der
My Line Schiffe.<br>
</CFCASE>
<CFCASE VALUE="spa">
Unase a raas
de 50 millones de visitantes que han
palpado la<br>
emocion de descubrir
a Nueva York a bordo de un barco
de My Line.<br>
</CFCASE>
<CFDEFAULTCASE>
</CFDEFAULTCASE>
</CFSWITCH> </FONT> </TD></TR> </table>
<CFIF isDefinedt"Cookie.commercial")
is False>
<!--- Устанавливаем
Cookie-"commercial" --->
<CFCOOKIE
NAME="commercial" VALUE="1"
EXPIRES="12/31/2001">
<CFELSE>
<CFIF tCookie.commercial*
eq 1> <script>
Variable = window.open("commercial.cfm",
"windowname", "top-10, lQft=530, width=2bU, neight=49U"
);
</script>
</CFIF> </CFIF>
<CFELSE>
<!--- Cookie.language не определен --->
<DIV id="prompt">
<TABLE border='0' cellspacing='0' cellpadding='0'>
<TR><TD width='400' class='clProrapt' align='right> New York's BEST<br>
Sightseeing and<br>Live Music<br>Cruises <TD></TR>
</TABLE>
</DIV>
<FORM method='post'
name='forml'>
<TABLE border='0'
cellspacing='2' cellpadding='0'>
<TR><TD colspan="2" width="400" align="center" bgcolor="#666699">
<FONT size="5"
color="White" face="Futura XBlk BT">
MY-LINE CRUISES
</FONT></TD></TR>
<TR><TD colspan="2" bgcolor="#666699" height=lx/TD></TR>
<TR><TD
colspan="2" valign="bottom" align="center"
height="342">
<IMG src="picl.gif" alt="" border="0" usemap="#MyMap"> </TD></TR>
<TR><TD
class="clRemLang">
<input type="checkbox"
name="RemLang" value="Yes" checked
onChange="javascript:chbRemLang(this.value);">
To remember the chosen language of viewing </TD>
<TD align="right">
<A HREF="javascript:myLink('rus');"
onMouseOver="javascript:layerWrite('prompt',null,
'-stable border=\'0\' cellspacing=\'0\'
cellpadding-\' 0\'xtrxtd width-\ ' 400\ '
class=\'clPrompt\' align=\ ' right\'Нью-Йорк ОТЛИЧНО<br>
Осмотр достопримечательностей и<br> Живая музыка<br>Круизы<td></tr></table>') ;
window.status='Russian';
return true"
onMouseOut="window.status=''; return true">
<img src="rus.gif"
alt=""
border="0"></A>
<A HREF="javascript:myLink('eng');"
onMouseOver="javascript:layerWrite('prompt',null,
'<table border=\'0\' cellspacing=\'0\'
cellpadding=\'0\'><tr><td
width=\'400\'
ClaSS=\'ClPrompt\'
align=\'right\'>New York\'s BEST<br>Sightseeing
and<br>Live
Music<br>Cruises<td></tr></table>');
window.status='English';
return true"
onMouseOut="window.status-''; return true">
<img src="eng.gi£"
alt=""
border="0"></A>finbsp;
<A HREF="javascript:myLink('ger');"
onMouseOver="javascript:layerWrite('prompt',null,
'<table border=\'0\' cellspacing=\'0\' cellpadding=\
' 0\ '><tr><td width=\' 400\ ' class=\'
clPrompt\' align=\' right\' >... <td></tr></table>'.);
window.status='Germanic';
return true"
onMouseOut="window.status='';
return true"><irag
src="ger.gif" alt=""
border="0"x/A>
<A HREF="javascript:myLink('spa');"
onMouseOver="javascript:layerWrite('prompt',null,'
<table border=\'0\' cellspacing=\'0\'
cellpadding=\'0\'><tr><td width=\'400\'
class=\'clPrompt\' align=\'right\'>...<td></tr></table>');
window.status='Spanish'; return true"
onMouseOut="window.status='';
return true"><img
src="spa.gif" alt=""
border="0"></A>
</TDX/TRX/TABLE> </FORM> <MAP name="MyMap">
<AREA alt="Sightseeing
Cruises" coords="45,205,188,217"
href="SightseeingCruises.cfm">
<AREA alt="Harbor
Lights Evening" coords="45,236,188,248"
href="HarborLightsEvening.cfm">
<AREA alt="Special
Events" coords="45,267,188,280"
href="SpecialEvents.cfm"> </map> </CFIF>
</BODY>
</HTML>
В коде страницы
my_line.cfm присутствуют ссылки на следующие файлы:
<A HREF="javascript:myLink('eng');"
onMouseOver="javascript:layerWrite('prompt',null,
'<table border=\'0\' cellspacing=\'0\' cellpadding=\'0\'><tr><td
width=\'400\' Class=\'clPrompt\' align=\'right\'>New York\'s
BEST<br>Sightseeing and<br>Live Music<br>Cruises<tdx/trX/table>');
window.status='English';
return true"
onMouseOut="window.status='';
return true"><img
src="eng.gif" alt=""
border="0"></A>
<A HREF="javascript:myLink('ger');"
onMouseOver="javascript:layerWrite('prompt',null,
'<table border=\'0\' cellspacing=\'0\'
cellpadding=\ ' 0\'><tr><td width=\ '
400\ ' class=\ ' clPrompt\ ' align=\ '
right\ ' >. . . <td></tr></table>'.) ;
window.status='Germanic';
return true"
onMouseOut="window.status='';
return true"><img
src="ger.gif" alt=""
border="0"></A>
<A HREF="javascript:myLink('spa')
; "
onMouseOver="javascript:layerWrite('prompt',null,'<table border=\'0\'
cellspacing=\'0\' cellpadding=\ ' 0\'><tr><td width=\ ' 400\ '
class=\'clPrompt\' align=\'right\'>...<td></tr></table>'};
window.status='Spanish';
return true" onMouseOut="window.status='';
return true"><img
src="spa.gif" alt=""
border="0"></A> </TD></TR></TABLE> </FORM>
<MAP name="MyMap">
<AREA alt="Sightseeing
Cruises" coords="45,205,188,217"
href="SightseeingCruises.cfm">
<AREA alt="Harbor
Lights Evening" coords="45,236,188,248"
href="HarborLightsEvening.cfm">
<AREA alt="Special
Events" coords="45,267,188,280"
href="SpecialEvents.cfm"> </map> </CFIF>
</BODY>
</HTML>
В коде страницы
my_line.cfm присутствуют ссылки на следующие файлы:
Отметим,
не localhost или 127.0.0.1, как это освещалось в главе 6. Все достаточно
просто, обращаться к Web-серверу можно и по его имени. И если ваш сервер называется
myweb, то и указывать путь к нему вы можете как http://myweb/my-app/.
Для нашего
примера, выбрав на странице один из национальных флагов, предположим флаг Соединенных
Штатов, загрузится англоязычная часть страницы myjine.cfm с указанными параметрами
. Если флажок То remember the chosen language of viewing (Сохранить выбранный
язык для просмотра)
будет отмечен, то при следующей загрузке мы сразу окажемся на англоязычной части
страницы.
Мы не описываем
страницу commercial.cfm с дополнительной информацией в силу простоты кода. Вы
можете разработать эту страницу самостоятельно.
Теперь давайте
разберем код страницы my_line.cfm без учета классических HTML-тегов и вспомогательных
текстов.
Таблица
7.2. Анализ кода страницы myjine.cfm
Код |
Описание |
||
<script>
function myLink(lang) { linecommand="window.
location. href = 'my line. cfm?language="+ |
Блок функций. Функция myLink
открывает страницу myjine.cfm с параметрами language И remlang. |
||
Код |
Описание |
||
+lang+"sremlang="+ |
Функция chbRemLang
использу- |
||
document . f
orml . RemLang . value+" ' " ; |
ется для переопределения
зна- |
||
eval (linecorttmand)
; |
чения элемента
RemLang формы |
||
|
form!. Элемент
RemLang имеет |
||
} |
тип checkbox
(флажок), значе- |
||
|
ние которого
не зависит от со- |
||
|
стояния флажка.
Это связано с |
||
function chbRemLang
(value) { |
тем, что форму
обычно исполь- |
||
if (value=='Yes
' ) { |
зуют с параметром
action, где |
||
document . f
orml . RemLang . value= ' No ' ; |
значение флажка
передается только в том случае, когда |
||
} else { |
флажок отмечен.
Нас это не |
||
document . f
orml . RemLang . value= ' Yes ' ; |
устраивает,
т. к. значение этого элемента мы отправляем в ка- |
||
} |
честве параметра
вручную. Вот |
||
) |
и приходится
"играть" на собы- |
||
|
тии onChange.
Если элемент |
||
</script> |
RemLang принимал
значение |
||
|
Yes, следовательно,
в момент |
||
|
изменения флажка
значение |
||
|
данного элемента
должно при- |
||
|
нять противоположное
значение. |
||
|
И наоборот |
||
<CFIF isDef
ined ( "Cookie . language" ) |
Если существует
Cookie. |
||
OR isDefined
("language") > |
language ил1/1
страница вклю- |
||
|
чает параметр
language, тогда |
||
|
в HTML-страницу
помещается |
||
|
код, расположенный
ниже |
||
|
вплоть до раздела
<CFELSE> |
||
<CFIF isDefined
('"Cookie . language" ) > |
Если существует
Cookie. |
||
<CFSET language=#Cookie
. language#> |
language, определяем
пере- |
||
|
менную language
независимо |
||
</CFIF> |
от ее существования |
||
<CFIF isDef
ined ( "remlang" ) > |
Если существует
параметр |
||
<CFIF remlang
eq "Yes"> |
remlang, равный
Yes (что ука- |
||
|
зывает на согласие
пользовате- |
||
<CFCOOKIE
NAME=" language" |
ля с необходимостью
запомнить |
||
VALUE="#language#" |
выбранный язык
просмотра), устанавливаем cookie равным |
||
EXPIRES="7"> |
language на
семь дней |
||
</CFIF> |
|
||
</CFIF> |
|
||
<CFSWITCH
EXPRESSlON=#language#> |
Используем тег
<CFSWITCH> |
||
<CFCASE VALUE="rus"> |
условного оператора. |
||
Русский текст
. . . |
Исходя из значения
переменной |
||
|
language, помещаем
необхо- |
||
</CFCASE> |
димый текст |
||
<CFCASE VALUE="eng"> |
|
||
Английский текст
. . . |
|
||
</CFCASE> |
|
||
<CFCASE VALUE="ger"> |
|
||
Немецкий текст
. . . |
|
||
</CFCASE> |
|
||
<CFCASE VALUE="spa"-> |
|
||
i |
|
||
Испанский текст
. . . |
|
||
</CFCASE> |
|
||
<CFDEFAULTCASE> |
|
||
</CFDEFAULTCASE> |
|
||
</CFSWITCH> |
|
||
<CFIF is
Defined ( "Cookie . commercial") |
Если не существует |
||
is False> |
Cookie . commercial,
устанав- |
||
<CCFCOOKIE
NAME="commercial" |
ливаем cookie
равным |
||
|
commercial до
31 декабря |
||
VALUE="1" |
2001 года |
||
EXPIRES="12/31/2001"> |
|
||
<CFELSE> |
Иначе. Cookie.
commercial |
||
<CFIF iCookie.
commercial! eq 1> |
определен и
равен 1. |
||
<script> |
Открываем страницу
commer- |
||
|
cial. cfm с
дополнительной ин- |
||
Variable = window.
open ( "commercial . cfm", |
формацией в
отдельном окне |
||
"windowname",
"top=10, left=530, |
|
||
width=250, height=490"
) ; |
|
||
</script> |
|
||
</CFIF> |
|
||
</CFIF> |
|
||
<CFELSE> |
Иначе. Cookie
. language не определен или отсутствует параметр language, тогда в
HTML-страницу помещается код, расположенный ниже вплоть до раздела
окончания тега оператора <CFIF> |
||
<FORM method='post
' name= ' forml ' > <input type="checkbox"
name="RemLang" value="Yes" checked onChange =
"javascript : chbRemLang (this .value) ; "> |
Формируем текст
первой страницы с формой выбора национального языка для дальнейшей
работы |
||
To remember
the chosen language of viewing |
|
||
<A HREF="
javascript :myLink ( ' rus ' ) ; "> |
|
||
<img src="rus
.gif " alt="" border="0"></A> |
|
||
<A HREF="
javascript :myLink( ' eng ' ) ; "> |
|
||
<img src="eng.gif
" alt="" border="0"x/A> |
|
||
<A HREF="
javascript :myLink( 'ger ' ) ; "> <img src="ger
. gif " alt="" border="0"></A> |
|
||
<A HREF="javascript:myLink(
'spa' } ; "> |
|
||
<img src="spa.
gif " alt="" border="0"></A> |
|
||
</FORM> |
|
||
</CFIF> |
Конец тега <CFIF>
условного оператора |
||
В качестве
самостоятельной работы можете попробовать совместить полученные знания о cookies
с примером из предыдущего урока, где при каждом открытии страницы welcome_flex.cfm
мы принуждали пользователя заполнять данные о себе, что, в общем-то, не всегда
разумно, если эти данные можно сохранить у клиента через браузер сразу же при
первом запросе. А при очередном открытии страницы считывать однажды введенные
значения cookies.
При этом еще раз отметим, что пользователь имеет возможность удалять cookies,
размещенные у него на компьютере.
Впрочем,
здесь вы можете при определении языка просмотра направлять пользователя на другую
заранее сформированную страницу, например на index_en.cfm в данном случае с
текстом на английском языке.
Существуют
и другие способы задания значений cookie, через теги <МЕТА> языка HTML,
JavaScript- и CGI-сценарии.
Подведем
итог. В данной главе мы использовали CFML-теги: <CFCOOKIE>, <CFSWITCH>/<CFCASE>/<CFDEFAULTCASE>.